﻿// 0909train01.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <limits>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <iomanip>

using namespace std;


/*
 SoloQ和koko是两兄弟，妈妈给了他们一大堆积木，每块积木上都有自己的重量
 现在他们想要将这些积木分成两堆。
哥哥Solo负责分配，弟弟koko要求两个人获得的积木总重量“相等”（根据Koko的逻辑）
个数可以不同，不然就会哭，但koko只会先将两个数转成二进制再进行加法，
而且总会忘记进位（每个进位都忘记）。如当25（11001）加11（1011）时，koko得到的
计算结果是18（10010）：
 11001
+01011
 10010

Solo想要尽可能使自己得到的积木总重量最大，且不让koko哭。
输入描述：
3
3 5 6
第一行是一个整数N(2≤N≤100），表示有多少块积木；第二行为空格分开的N个整数Ci(1≤Ci≤10^6），表示第i块积木的重量。
输出描述：
11
让koko不哭，输出Solo所能获得积木的最大总重量；否则输出“NO”。
 */
class Solution03
{
public:
    Solution03(vector<int>&num_vec)
    {
        int xor_sum = num_vec[0];
        for (int i=1; i<num_vec.size(); i++)
        {
            xor_sum = xor_sum ^ num_vec[i];
        }

        if (xor_sum!=0)
        {
            cout << "-1";
            return;
        }
            
        int sum = 0;
        for (auto&num:num_vec)
        {
            sum += num;
        }

        sort(num_vec.begin(), num_vec.end());

        cout << sum - num_vec[0];
        //Solution03
    }
};


/*
 有M(1<=M<=10)个端口组  
每个端口组是长度为N(1<=N<=100)的整数数组，
如果端口组间存在2个及以上不同端口相同，则认为这2个端口组互相关联，可以合并
第一行输入端口组个数M，再输入M行，每行逗号分隔，代表端口组。
输出合并后的端口组，用二维数组表示

输入描述
第一行输入一个数字M  
第二行开始输入M行，每行是长度为N的整数数组，用逗号分割

输出描述  
合并后的二维数组，用二维数组表示  
1：组合内同端口仅保留一个，并从小到大排序。  
2：组合外顺序保持输入顺序。  
示例1：  
输入：  
4  
4  
2,3,2  
1,2  
5  
输出：  
[[4],[2,3],[1,2],[5]]

示例2：
输入：
3
2,3,1
4,3,2
5
输出：
[[1,2,3,4],[5]]

示例3：
输入：
6
10
4,2,1
9
3,6,9,2
6,3,4
8
输出：
[[10],[1,2,3,4,6,9],[9],[8]]
 */
 /*
 示例2：
 输入：
 3
 2,3,1
 4,3,2
 5
 输出：
 [[1,2,3,4],[5]]
 */
class Solution01
{
public:
    vector<int>combineVec(vector<int>&a_vec, vector<int>&b_vec)
    {
        vector<int>result;

        unordered_map<int, int>a_map;
        for (auto&num:a_vec)
        {
            a_map[num] += 1;
        }

    	int same_count = 0;
        for (auto&num:b_vec)
        {
            if (a_map.count(num)>0 && a_map.at(num)>0)
            {
                same_count += 1;
                a_map[num] -= 1;
            }
        }
       
        if (same_count < 2) return result;

        unordered_set<int>prepare_set;
        for (auto&num:a_vec)
        {
            prepare_set.insert(num);
        }
        for (auto& num : b_vec)
        {
            prepare_set.insert(num);
        }

        for (auto&num:prepare_set)
        {
            result.push_back(num);
        }
        sort(result.begin(), result.end());
        return result;
        //combineVec
    }

    vector<vector<int>>getNewVec(
        vector<vector<int>>& exec_vec,
        vector<int>&combine_v, 
        int index_1, int index_2)
    {
        vector<vector<int>>new_vec;
        for (int i=0; i< exec_vec.size(); i++)
        {
            if (i==index_1)
            {
                new_vec.push_back(combine_v);
                continue;
            }
            if (i==index_2)
            {
                continue;
            }
            new_vec.push_back(exec_vec[i]);
        }
        return new_vec;
        //getNewVec
    }

    Solution01(vector<vector<int>>& origin_vec)
    {
        vector<vector<int>>exec_vec = origin_vec;
        while (true)
        {
            bool is_combine = false;
            //端口组间存在2个及以上不同端口相同，端口可以合并
            for (int i = 0; i < exec_vec.size(); i++)
            {
                for (int next = i + 1; next < exec_vec.size(); next++)
                {
                    //先查看当前是否可以合并
                    vector<int>combine_v = combineVec(exec_vec[i], exec_vec[next]);

                    if (!combine_v.empty())
                    {
                        exec_vec = getNewVec(exec_vec, combine_v, i, next);
                        is_combine = true;
                        break;
                    }

                }
                if (is_combine) break;
            }
            //break while循环
            if (!is_combine) break;

        }

        cout << '[';
        //最后输出的时候，去重
        for (int i=0; i<exec_vec.size(); i++)
        {
            vector<int>min_vec = exec_vec[i];
            unordered_set<int>min_set;
            for (auto&num:min_vec)
            {
                min_set.insert(num);
            }

            vector<int>sort_min_v;
            for (auto&num:min_set)
            {
                sort_min_v.push_back(num);
            }
            sort(sort_min_v.begin(), sort_min_v.end());

            cout << '[';
            for (int i=0; i<sort_min_v.size(); i++)
            {
                cout << sort_min_v[i];
                if (i!=sort_min_v.size()-1)
                {
                    cout << ',';
                }
            }
            cout << ']';

            if (i!=exec_vec.size()-1)
            {
                cout << ',';
            }
        }
        cout << ']';
	    //Solution01
    }
};


/*
 题目描述
用一个数组A代表程序员的工作能力，公司想通过结对编程的方式提高员工的能力，
假设结对后的能力为两个员工的能力之和，求一共有多少种结对方式使结对后能力为N

输入描述
第一行为员工的总人数，取值范围[1,1000]
第二行为数组A的元素，每个元素的取值范围[1,1000]
第三行为N的值，取值范围[1,1000]

输出描述
满足结对后能力为N的结对方式总数

输入
5
1 2 2 2 3
4
输出
4

满足要求的结对方式为：A[0]和A[4]，A[1]和A[2]，A[1]和A[3]，A[2]和A[3]
 */
class Solution02
{
public:
    Solution02(vector<int>&num_vec, int target)
    {
        unordered_map<int, vector<int>>num_map;

        int result = 0;
        for (int i=0; i<num_vec.size(); i++)
        {
            for (int next=i+1; next<num_vec.size(); next++)
            {
	            if (num_vec[i]+num_vec[next]==target)
	            {
                    result += 1;
	            }
            }
        }
        cout << result;
        //Solution02
    }
};

int main()
{
	{
        int num1 = 3, num2 = 5^6;
        int result = num1 ^ num2;
        cout << result;

        return 0;
	}
	{

        int v_size;
        cin >> v_size;

        vector<int>num_vec(v_size);

        for (int i=0; i<v_size; i++)
        {
            cin >> num_vec[i];
        }

        Solution03 solu(num_vec);

        return 0;
	}
	{
/*
5
1 2 2 2 3
4
*/
        int v_size;
        cin >> v_size;

        vector<int>num_vec(v_size);
        for (int i=0; i<v_size; i++)
        {
            cin >> num_vec[i];
        }

        int target;
        cin >> target;

        Solution02 solu(num_vec, target);

        return 0;
	}
    int v_size;
    cin >> v_size;
    cin.ignore();

    vector<vector<int>>origin_vec;
    string input;
    for (int i=0; i<v_size; i++)
    {
        getline(cin, input);
        stringstream oh_sstream1(input);
        vector<int>origin_min_vec;

        string token;
        while (getline(oh_sstream1, token, ','))
        {
            origin_min_vec.push_back(stoi(token));
        }
        origin_vec.push_back(origin_min_vec);
    }

    Solution01 solu(origin_vec);

}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件
